--
-- Author: shineflag
-- Date: 2017-03-12 14:43:56
--
-- Desc: 关键数的加减操作


local skynet = require "skynet"
local log = require "log"
local json = require("json")
local cts = require("constants")
local redis = require "skynet.db.redis"
local mysql = require "skynet.db.mysql"

local TAG = "MDATA"

local logcenter   --日志中心

--ginfo 中的hash key
local gkeys = {
	"money",
	"diamond" ,
	"score",
}

local rdb     --redis数据库
local pokaa_db   --mysql数据库
local mdata_save  --将改动的redis数据更新到数据库
local CMD = {}

local function connect_pokaa_db()
	local function on_connect(db)
		db:query("set charset utf8mb4")
		db:query("set names utf8") 
		log.e(TAG, "pokaa db connected!")
	end

	local mconf = require("mysql_conf")

	log.e(TAG,"start connect mysql %s:%d",mconf.host, mconf.port)
	pokaa_db = mysql.connect({
		host = mconf.host,
		port = mconf.port,
		database = mconf.database,
		user = mconf.user,
		password = mconf.password,
		max_packet_size=1024*1024,
		on_connect=on_connect
		})

	if not pokaa_db then
		log.e(TAG,"failed to connect db")
		skynet.exit()
	end
end

local function redis_connect()
	local rconfs = require("redis_conf")
	local rport = rconfs["redis_mdata"]
	local rconf = rconfs[rport]
	local conf = {
		host = rconf.host,
		port = rconf.port,
		db = 0
	}
	log.e(TAG,"start connect redis %s:%d",conf.host, conf.port)
	rdb = redis.connect(conf)
end


--将用户的金币变化日志落地到文件
local function retport_mdata_log(mid, cmoney, tmoney, tkey)
	local info = {
		mid = mid,
		cmoney = cmoney,
		tmoney = tmoney,
		tkey = tkey,
		tunix = os.time()
	}

	local log_str = json.encode(info)
	log.d(TAG,"mdata log [%s]", log_str)
	skynet.send(logcenter, "lua", "record", "mdata", log_str)
end


--将redis 字符串数组 形式的结果转换成 table 形式
local function rdata2table(data)
	local t = {}
	for id = 1, #data, 2 do 
		t[data[id]] = data[id+1]
	end

	return t
end

--通知mid的数据有改动，需要更新到数据
local function notify_ginfo_save(mid)
	skynet.send(mdata_save,"lua","ginfo",mid)
end

--从mysql获取用户的游戏
local function mysql_ginfo(mid)
	local sql = string.format("SELECT money, diamond, score FROM pokaa_gameinfo WHERE mid=%d",mid)
	local res =  pokaa_db:query(sql)
	log.d(TAG,"after sql[%s] res[%s]",sql, json.encode(res))
	k,row_data = next(res)
	if not row_data then 
		log.d(TAG,"failed sql[%s] err[%s]",sql, res.err) 
		return nil 
	end

	return row_data 
end

--将用户的信息插入到redis
local function hmset_ginfo(mid,info)
	local gkey = string.format("ginfo_%d",mid)
	local rt = {gkey}   --redis 用
	for _, v in pairs(gkeys) do 
		table.insert(rt,v)
		table.insert(rt,info[v] or 0)
	end

	local ret = rdb:hmset(rt)
	log.d(TAG,"ret[%s] hmset %s ",json.encode(ret),table.concat(rt, " "))
	
end

--加减hash key 某字段 数值
local function hincr(key,field,num)
	local  param = {key,field,num}
	local ret = rdb:hincrby(param)
	log.d(TAG,"call HINCRBY %s  #ret[%s]",table.concat(param, " "),ret)
	if not ret  then
		log.e(TAG,"faild call HINCRBY %s",table.concat(param, " "))
		return false
	else
		return tonumber(ret)
	end
end

local function get_ginfo_field(mid,field)
	local param = {
		string.format("ginfo_%d",mid),
		field,
	}

	local ret = rdb:hget(param)
	log.d(TAG,"call HGET %s  :ret[%s]",table.concat(param," "),ret)
	if not ret  then
		local data = mysql_ginfo(mid)
		if data then 
			hmset_ginfo(mid, data)
			return tonumber(data[field]) 
		end
		return false 
	else
		return tonumber(ret)
	end
end

--改变用户的积分
local function change_score(mid, num, k)
	log.e(TAG,"mode[%s] chage user[%d] score[%d]",k,mid,num)
	local gkey = string.format("ginfo_%d",mid)
	local left = hincr(gkey,"score", num)
	notify_ginfo_save(mid)
	log.e(TAG,"mode[%s] chage user[%d] score[%d] left[%d]",k,mid,num,left)

	retport_vdata_log(mid, num, left, k)
	return left
end


--改变用户的金币
local function change_money(mid, num, k)
	local gkey = string.format("ginfo_%d",mid)
	local left = hincr(gkey,"money", num)
	notify_ginfo_save(mid)
	log.e(TAG,"mode[%s] chage user[%d] money[%d] left[%d]",k,mid,num,left)

	retport_mdata_log(mid, num, left, k)
	return left
end

--改变用户的筹码
local function change_coin(mid,field,num, k)
	local ckey = string.format("gcoin_%d",mid)
	local cur = hincr(ckey,field, num)
	log.e(TAG,"mode[%s] chage user[%d] field[%s] coin[%d] cur[%d]",k,mid,field,num,cur)
	return cur
end

--获取某个域的筹码
local function get_filed_coin(mid, field)
	local param = {
		string.format("gcoin_%d",mid),
		field
	}

	local ret = rdb:hget(param)
	log.d(TAG,"call HGET %s  :ret[%s]",table.concat(param," "),ret)
	if not ret  then
		return false 
	else
		return tonumber(ret)
	end

end

--初始化用户的游戏信息
function CMD.register(mid, info )
	local gkey = string.format("ginfo_%d",mid)
	if rdb:exists(gkey) then
		log.d(TAG,"exist user[%d]",mid)
		return false 
	elseif mysql_ginfo(mid) then
		return false
	end



	local mt = {}   --mysql sql 用
	for _, v in pairs(gkeys) do 
		if info[v] then 
			mt[v] = info[v] 
		else
			mt[v] = 0 
		end
	end

	local sql = string.format("INSERT INTO pokaa_gameinfo (`mid`,`money`, `diamond`, `score`) VALUES (%d, %d, %d, %d)",
		mid, mt.money, mt.diamond, mt.score)
	local res = pokaa_db:query(sql)
	log.d(TAG,"after sql[%s] res[%s]",sql, json.encode(res))
	
	hmset_ginfo(mid,mt)

	retport_mdata_log(mid, info.money, info.money, cts.mregister )
	return true 
end

--更新用户的信息
function CMD.update(mid, info)
	local t = {string.format("ginfo_%d",mid)}
	for _,key in pairs(gkeys) do 
		if info[key] then 
			table.insert(t, key)
			table.insert(t. info[key])
		end
	end
	return rdb:hmset(t)
end


--获取用户的所有游戏信息
function CMD.getall( mid )

	local gkey = string.format("ginfo_%d",mid)
	local ret  = rdb:hgetall(gkey)
	log.d(TAG,"ret[%s]",json.encode(ret))
	if not ret or not next(ret) then 

		local data = mysql_ginfo(mid)
		if data then 
			hmset_ginfo(mid, data)
			return true, data 
		else
			return false 
		end

	else
		return true, rdata2table(ret)
	end
end

function CMD.getscore(mid)
	return get_ginfo_field(mid, "score")
end
--[[
	desc:改变用户的vip积分
    param:  num:改变的数量， k:改变的类型
--]]
function CMD.changescore(mid, num, k)
	local score = get_ginfo_field(mid, "score")
	if not score or score + num < 0 then 
		return false 
	else
		local left = change_score(mid, num, k)
		return left
	end
end

function CMD.getmoney(mid)
	return get_ginfo_field(mid, "money")
end

--[[
	desc:改变用户的金币
    param:  num:改变的数量， k:改变的类型
--]]
function CMD.changemoney(mid, num, k)
	local money = get_ginfo_field(mid, "money")
	if not money or money + num < 0 then 
		return false 
	else
		local now_money = change_money(mid, num, k)
		return now_money
	end
end


--用户购买筹码
function CMD.buycoin(mid,lv,tid,coin)
	local money = CMD.getmoney(mid)
	if money < coin then 
		return false 
	else
		local coin_field = string.format("%d_%d",lv,tid)
		local now_money = change_money(mid, -coin, cts.mbuycoin)
		local now_coin = change_coin(mid,coin_field,coin, cts.cbuy)
		return now_coin, now_money
	end
end

 --用户赎回筹码
function CMD.redeemcoin(mid,lv,tid)

	local field = string.format("%d_%d",lv,tid)
	local coin = get_filed_coin(mid,field)
	local now_coin = change_coin(mid,field,-coin, cts.credeem)
	local now_money = change_money(mid, coin, cts.mredeem)
	local param = {string.format("gcoin_%d",mid), field}
	rdb:hdel(param)
	return now_money
end

skynet.start(function ( ... )

	connect_pokaa_db()
	redis_connect()
	mdata_save = skynet.uniqueservice "mdata_save"
	logcenter = skynet.uniqueservice "logcenter/logagent"
	
	skynet.dispatch("lua", function( session,address, cmd,... )
		local f = CMD[cmd]
		if f then
			if session ~= 0 then
		   		skynet.ret(skynet.pack( f(...) ) )
		   	else
		   		f(...)
		   	end 
		else
		    log.e(TAG,string.format("address[%d] call not exist cmd[%s] ",address,cmd) )
	    end
	end)   

end)